import asyncio
import json
from typing import Optional
from dotenv import load_dotenv
from pathlib import Path
from contextlib import AsyncExitStack
from openai import OpenAI
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import os

import httpx

load_dotenv()  # 加载环境变量

# os.environ["HTTPS_PROXY"] = "http://localhost:8080" 
# os.environ["HTTP_PROXY"] = "http://localhost:8080" 


class MCPClient:
    def __init__(self):
        """初始化MCP客户端"""

        api_key = os.getenv("BAILIAN_KEY")
        base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
        self.model = "qwen3-32b"  

        http_client = httpx.Client(
            # proxy="http://localhost:8080",
            verify=False,
        )

        self.client = OpenAI(
            api_key=api_key,
            base_url=base_url,
            http_client=http_client,
        )
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()

    async def connect_to_server(self):
        """连接到MCP服务器并列出MCP服务器的可用工具函数"""

        server_script_path = Path(__file__).parent / "mcp_server.py"
        # 启动MCP服务器并建立通信
        self.stdio, self.write = await self.exit_stack.enter_async_context(
            stdio_client(
                StdioServerParameters(
                    command="python", args=[str(server_script_path)], env=None
                )
            )
        )
        self.session = await self.exit_stack.enter_async_context(
            ClientSession(self.stdio, self.write)
        )

        await self.session.initialize()  # 与服务器建立stdio连接

        # 列出MCP服务器上的工具
        response = await self.session.list_tools()
        tools = [tool.name for tool in response.tools]
        print("\n已连接到服务器，支持以下工具:", tools)

    async def process_query(self, query: str) -> str:
        """使用大模型处理查询并调用MCP Server可用的MCP工具"""
        messages = [{"role": "user", "content": query}]
        response = await self.session.list_tools()

        available_tools = [
            {
                "type": "function",
                "function": {
                    "name": tool.name,
                    "description": tool.description,
                    "input_schema": tool.inputSchema,
                },
            }
            for tool in response.tools
        ]

        response = self.client.chat.completions.create(
            model=self.model, messages=messages, tools=available_tools
        )

        # 处理返回内容
        content = response.choices[0]
        if content.finish_reason == "tool_calls":
            # 返回结果是使用工具的建议，就解析并调用工具
            tool_call = content.message.tool_calls[0]
            tool_name = tool_call.function.name
            tool_args = json.loads(tool_call.function.arguments)
            # 执行工具
            result = await self.session.call_tool(tool_name, tool_args)
            print(f"\n\n[Calling tool {tool_name} with args {tool_args}]\n\n")
            # 将模型返回的调用工具的对话记录保存在messages中
            messages.append(content.message.model_dump())
            messages.append(
                {
                    "role": "tool",
                    "content": result.content[0].text,
                    "tool_call_id": tool_call.id,
                }
            )

            print(messages)
            print("\n\n")
            # 将上面的结果返回给大模型用于生产最终结果
            response = self.client.chat.completions.create(
                model=self.model, messages=messages
            )
            return response.choices[0].message.content
        return content.message.content

    async def chat_loop(self):
        """运行交互式聊天"""
        print("\n MCP客户端已启动！输入quit退出")
        while True:
            try:
                query = input("\问题:").strip()
                if query.lower() == "quit":
                    break
                response = await self.process_query(query)
                print(f"\nAnswer: {response}")
            except Exception as e:
                print(f"发生错误: {str(e)}")

    async def close(self):
        await self.exit_stack.aclose()


async def main():
    client = MCPClient()
    try:
        await client.connect_to_server()
        await client.chat_loop()
    finally:
        await client.close()


if __name__ == "__main__":
    asyncio.run(main())
